package com.github.codemperor.core.logger;

import com.github.codemperor.core.token.CurrentUserInfo;
import com.github.codemperor.core.token.context.CurrentUserContext;
import com.github.codemperor.core.util.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 顶级日志父类抽象
 */
public abstract class BaseLogger {
    private Logger log;
    private final LogDomainTypeEnum type = LogDomainTypeEnum.DEFAULT; // 默认类型为default，随意打日志。基本不统计，只有有真正业务类型的日志才需要统计
    private static final String SEPARATOR = " ~ ";
    protected Class clazz;

    /**
     * 日志类型，根据业务划分。每个继承的子类可以设定自己的业务类型
     *
     * @return
     */
    protected abstract LogDomainTypeEnum type();

    /**
     * 提供自定义扩展信息接口，子类可以在日志内容前，以~分隔，打印比较重要的信息，比如金额、订单号等
     *
     * @return
     */
    protected abstract String extend();

    /**
     * 获取服务名称
     *
     * @return
     */
    private String getServerName() {
        try {
            return PropertyUtils.getPropertiesValue("${spring.application.name}");
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 2019-11-21 12:07:22,237 ~ [http-nio-9002-exec-1] ~ INFO  ~ UserRouter ~ update-auth ~ WEBSITEUSER123945645-2342345-123 ~ WEBSITEUSER ~ 0:0:0:0:0:0:0:1 ~ /api/authorized/auth/website/current/user/info ~ zl592886931@gmail.com ~ [getWebsiteCurrentUserInfo]
     * 2019-11-21 12:07:22,237 ~ [http-nio-9002-exec-1] ~ INFO  ~ UserRouter ~ update-auth ~ WEBSITEUSER_LOGIN ~ aoifadf-123-123-123 ~ 0:0:0:0:0:0:0:1 ~ /api/authorized/auth/website/current/user/info ~ zl592886931@gmail.com ~ [getWebsiteCurrentUserInfo]
     * 2019-11-21 12:07:22,237 ~ [http-nio-9002-exec-1] ~ INFO  ~ UserRouter ~ update-auth ~ WEBSITEUSER_REGISTERTEST ~ 12312312-3123sjkndf-123 ~ 0:0:0:0:0:0:0:1 ~ /api/authorized/auth/website/current/user/info ~ zl592886931@gmail.com ~ TTT1 ~ TTT2 ~ [getWebsiteCurrentUserInfo]
     * 1: 日期
     * 2: 线程号
     * 3: 日志级别
     * 4: 类名
     * 5: 服务名称
     * 6: 业务类型，用于区分业务，格式为: 业务_子业务1_子子业务1，这样在查询父业务的时候可以统一查到
     * 7: 唯一请求号，没有此请求号说明要么是异步，要么是非网关请求
     * 8: ip地址
     * 9: 调用的api
     * 10: 用户email
     * 10到end之间: 日志自定义重要前缀，比如订单号 ~ 订单价格 ~ 订单日期
     * end: 日志输出内容
     * 数组记得减一
     *
     * @param content
     * @return
     */
    //获取需要打印的日志内容
    private String getPrintContent(String content) {
        CurrentUserInfo user = CurrentUserContext.get();
        if (null == user) {
            user = new CurrentUserInfo();
        }

        //获取日志类型
        String type = type() == null ? this.type.name() : type().name();
        //获取日志固定前缀
        String desc = getServerName() + SEPARATOR +
                type + SEPARATOR +
                user.getRequestNo() + SEPARATOR +
                user.getRemoteHostAddress() + SEPARATOR +
                user.getUri() + SEPARATOR +
                user.getUserEmail();

        //处理子类自定义的重要信息前缀
        String importantPrefix = extend();
        if (!StringUtils.isEmpty(importantPrefix)) {
            if (importantPrefix.endsWith(SEPARATOR)) { //最后一位是分隔符，就去掉
                importantPrefix = importantPrefix.substring(0, importantPrefix.lastIndexOf(SEPARATOR));
            }
        }
        desc = desc + SEPARATOR + importantPrefix; //无论是否有扩展位，都需要占位

        //拼接子类打印的日志内容
        desc = desc + SEPARATOR + content.replaceAll(SEPARATOR, "-");
        return desc;
    }

    //实例化日志log
    protected BaseLogger(Class clazz) {
        this.log = LoggerFactory.getLogger(clazz);
        this.clazz = clazz;
    }

    public void debug(String desc, Object... argArray) {
        log.debug(getPrintContent(desc), argArray);
    }

    public void info(String desc, Object... argArray) {
        log.info(getPrintContent(desc), argArray);
    }

    public void trace(String desc, Object... argArray) {
        log.trace(getPrintContent(desc), argArray);
    }

    public void warn(String desc, Object... argArray) {
        log.warn(getPrintContent(desc), argArray);
    }

    public void error(String desc, Object... argArray) {
        log.error(getPrintContent(desc), argArray);
    }

    /**
     * 获取日志类型（业务类型）
     *
     * @param msg 日志内容
     * @return
     */
    public static String getType(String msg) {
        if (msg == null || msg.length() <= 0) {
            return null;
        }
        List<String> list = Arrays.asList(msg.split(SEPARATOR));
        if (list.size() <= 0) {
            return null;
        }
        String type = list.get(0);
        return null == type ? null : type.trim();
    }

    /**
     * 按照参数顺序转化成日志消息类型，以~分隔
     *
     * @param msg 日志内容
     * @return
     */
    public static String conver(String... msg) {
        if (msg == null || msg.length <= 0) {
            return null;
        }
        List<String> list = Arrays.asList(msg);
        if (list.size() <= 0) {
            return null;
        }
        return String.join(SEPARATOR, list);
    }

    /**
     * 解析数据，转为list
     *
     * @param msg 日志内容
     * @return
     */
    public static List<String> resolver(String msg) {
        if (msg == null) {
            return new ArrayList<>();
        }
        return Arrays.asList(msg.split(SEPARATOR));
    }
}
